package GsGate

import (
	"encoding/json"
	"net"
	"time"
	. "tksConfig"
	. "tksLog"
	. "tksStatic"
	. "tksTcp"
	. "tksUint"
)

const (
	GateStateInitialized uint32 = iota
	GateStateConnected
	GateStateRegistering
	GateStateRegistered
)

type GateInfo struct {
	Host         string
	Gate         *TksTcpConn
	TimeoutCount int
	t            *time.Ticker
	State        uint32
	done         chan uint32
	ct           chan int
}

var Gates map[int]*GateInfo

func (g *GateInfo) run() {
	id, _ := Config.Get("server").Get("id").Int()
	//
	var req GateHeartbeatReq
	req.Any = true
	data, _ := MsgToBuf(req)
	for {
		if g.State == GateStateInitialized {
			//connect
			gate, err := NewClient(g.Host)
			if err != nil {
				Debug("connect gate[%d]: %s, error: %s", id, g.Host, err)
				time.Sleep(time.Second * 5) //wait 5 second, then try again.
				continue
			}
			g.Gate = gate
			g.State = GateStateConnected
			Debug("connect  gate: %s success", g.Host)
		} else if g.State == GateStateConnected {
			//register
			var connReq ServerConnectGateReq
			connReq.Id = uint32(id)
			connData, _ := MsgToBuf(connReq)
			SendBuffer(g.Gate.Conn, CmdServerConnectGateReq, uint32(id), 0, connData)
			Debug("register  gate: %s begin", g.Gate.Conn.RemoteAddr().String())
			g.State = <-g.done
			Debug("register  gate: %s success", g.Gate.Conn.RemoteAddr().String())
		} else if g.State == GateStateRegistered {
			select {
			case g.TimeoutCount = <-g.ct:
				continue
			case <-g.t.C:
				Debug("send Heartbeat to gate: %s", g.Gate.Conn.RemoteAddr().String())
				SendBuffer(g.Gate.Conn, CmdGateHeartbeatReq, uint32(id), 0, data)
				if g.TimeoutCount > 3 {
					g.State = GateStateInitialized
					g.Gate = nil
				} else if g.TimeoutCount > 0 {
					g.TimeoutCount = g.TimeoutCount + 1
				} else {
					break
				}
			}
		}

	}
}

func ConnectAllGate() bool {
	Gates = make(map[int]*GateInfo)
	//
	RegisterServerCmd(CmdGateHeartbeatRsp, RecvHeartbeatRsp)
	RegisterServerCmd(CmdServerConnectGateRsp, RecvConnectGateRsp)
	//
	gate, _ := Config.Get("gate").Array()
	for k, v := range gate {
		host, _ := (v.(map[string]interface{}))["host"]
		port, _ := (v.(map[string]interface{}))["port"]
		info := new(GateInfo)
		info.Host = host.(string) + ":" + string(port.(json.Number))
		info.State = GateStateInitialized
		info.TimeoutCount = 0
		info.done = make(chan uint32)
		info.ct = make(chan int)
		Gates[k] = info
	}
	for _, gate := range Gates {
		Debug("======= run gate host: %s", gate.Host)
		go gate.run()
	}
	return true
}

func RecvHeartbeatRsp(conn net.Conn, from uint32, to uint32, buf []byte) {
	Debug("recv  gate  Heartbeat Rsp from %s ", conn.RemoteAddr().String())
	for _, gate := range Gates {
		if gate.Gate.Conn.RemoteAddr().String() == conn.RemoteAddr().String() {
			gate.ct <- 0
		}
	}
}

func RecvConnectGateRsp(conn net.Conn, from uint32, to uint32, buf []byte) {
	Debug("recv  gate  register Rsp from %s ", conn.RemoteAddr().String())
	for _, gate := range Gates {
		if gate.Gate.Conn.RemoteAddr().String() == conn.RemoteAddr().String() {
			Debug("===========%s", gate.Gate.Conn.RemoteAddr().String())
			gate.done <- GateStateRegistered
			gate.t = time.NewTicker(5 * time.Second)
		}
	}
}
